﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace OttoEngineSimulation
{
    public partial class SeitenAnsichtZylinder : UserControl
    {
        private enum Takt
        {
            AnsaugTakt,
            VerdichtungsTakt,
            ExplosionsTakt,
            AbsaugTakt,
            DerSelbe
        }


        private Takt takt;
        private float ansaugPunktX;
        private float verdichtungsPunktY;
        private float explosionsPunktX;
        private float absaubungsPunktY;

        private bool init;

        private int halbZaehler;
        RectangleF KurbelWelleRechtEck;

        RectangleF nockenWelleRechtEck;
        private int nockenWelleRadius = 70;
        private float nockenWelleMitteX;
        private float nockenWelleMitteY;

        Rectangle zylinderHuelle;
        private int zylinderBreite = 170;
        private int zylinderHoehe = 40;
        Point zylinderPosition;
        Point zylinderUntenRechtspkt;
        Pen zylinderFarbe = new Pen(Color.Black);

        private Rectangle einlassVentil;
        private Rectangle auslassVentil;
        private int ventilbreite = 10;
        private int ventilhoehe = 10;


        private Rectangle zuendKerze;
        private int zuendKerzeBreite = 20;
        private int zuendKerzeHoehe = 5;


        private Rectangle einlassStange;
        Point einlassStangeDefaultLoc;
        Point einlassStangeVerschiebeLoc;
        private int einlassStangeBreite = 250;
        private int einlasswStangeHoehe = 10;


        private Rectangle auslassStange;
        Point auslassStangeDefaultLoc;
        Point auslassStangeVerschiebeLoc;
        private int auslassStangeBreite = 250;
        private int auslassStangeHoehe = 10;


        Point kolbenPosition;
        Size kolbenSize;
        Rectangle kolben;
        private int kolbenBreite = 40;
        private int kolbenLaenge = 40;


        private float winkel;

        private float ventilWinkel;

        private int radius = 35;

        private float kreisMitteX = 80;
        private float kreisMitteY = 50;

        private float stangenLaenge = 150;



        public bool Init
        {
            set { this.init = value; }
        }
        public int HalbZaehler
        {
            set { this.halbZaehler = value; }
        }

        public float Winkel
        {
            set { this.winkel = value; }
        }

        public float VentilWinkel
        {
            set { this.ventilWinkel = value; }
        }
        public SeitenAnsichtZylinder()
        {
            InitializeComponent();
            this.init = true;
            this.halbZaehler = 0;
            this.nockenWelleRadius = this.radius * 2;
            this.ErzeugeZylinderHuelle();
            this.ErstelleKurbelWelle();
            this.ErzeugeNockenWelle();
            this.BerechneTaktPunkt();
            this.ErstellVentile();
            this.ErstellZuendkerze();
            this.ErstelleEinlassStange();
            this.ErstellAuslausStange();
            this.ErstelleKolben();

        }

        private void ErstelleEinlassStange()
        {
            int xPosition = (int)this.nockenWelleMitteX + this.nockenWelleRadius + 5;
            int yPosition = (int)this.nockenWelleMitteY - this.einlasswStangeHoehe / 2;
            this.einlassStangeDefaultLoc = new Point(xPosition, yPosition);
            this.einlassStangeVerschiebeLoc = new Point(xPosition + 5, yPosition);
            this.einlassStange = new Rectangle(xPosition, yPosition, this.einlassStangeBreite, this.einlasswStangeHoehe);
        }

        private void ErstellAuslausStange()
        {
            int xPosition = (int)this.kreisMitteX + 10;
            int yPosition = (int)this.kreisMitteY + this.radius + 10;
            this.auslassStangeDefaultLoc = new Point(xPosition, yPosition);
            this.auslassStangeVerschiebeLoc = new Point(xPosition + 10, yPosition);
            this.auslassStange = new Rectangle(xPosition, yPosition, this.auslassStangeBreite, this.auslassStangeHoehe);
        }

        private void ErstellZuendkerze()
        {
            int xpostion = this.zylinderHuelle.Right - this.zuendKerzeBreite / 2;
            int yposition = this.zylinderHuelle.Top + 17;
            this.zuendKerze = new Rectangle(xpostion, yposition, this.zuendKerzeBreite, this.zuendKerzeHoehe);
        }

        private void ErstellVentile()
        {
            int einlassVentilX = this.zylinderHuelle.Right - this.ventilbreite / 2;
            int einlassVentilY = this.zylinderHuelle.Top + 5;
            this.einlassVentil = new Rectangle(einlassVentilX, einlassVentilY, this.ventilbreite, this.ventilhoehe);
            int auslassVentilX = this.zylinderHuelle.Right - this.ventilbreite / 2;
            int auslassVentilY = this.zylinderHuelle.Bottom - 15;
            this.auslassVentil = new Rectangle(auslassVentilX, auslassVentilY, this.ventilbreite, this.ventilhoehe);
        }

        private void ErstelleKolben()
        {
            this.kolbenSize = new Size(this.kolbenBreite, this.kolbenLaenge);
            this.kolben = new Rectangle(this.kolbenPosition, this.kolbenSize);
        }
        private void ErstelleKurbelWelle()
        {
            this.KurbelWelleRechtEck = new RectangleF(
                     this.kreisMitteX - this.radius, this.kreisMitteY - this.radius,
                     2 * this.radius, 2 * this.radius);
        }

        private void ErzeugeZylinderHuelle()
        {
            //  this.zylinderBreite = (int)this.kolbenBreite + (int)this.stangenLaenge;
            this.zylinderUntenRechtspkt = new Point(this.zylinderBreite, this.zylinderHoehe);
            float xposition = this.kreisMitteX + this.radius + this.kolbenBreite;
            float yposition = this.kreisMitteY - this.zylinderHoehe / 2;
            this.zylinderPosition = new Point((int)xposition, (int)yposition);
            this.zylinderHuelle = new Rectangle(this.zylinderPosition, new Size(this.zylinderUntenRechtspkt));
        }

        private void ErzeugeNockenWelle()
        {
            this.nockenWelleMitteX = this.kreisMitteX;

            this.nockenWelleMitteY = this.kreisMitteY + this.radius + this.nockenWelleRadius + 20;
            this.nockenWelleRechtEck = new RectangleF(
                this.nockenWelleMitteX - this.nockenWelleRadius, this.nockenWelleMitteY - this.nockenWelleRadius,
                this.nockenWelleRadius * 2, this.nockenWelleRadius * 2);

        }

        private void BerechneTaktPunkt()
        {
            this.ansaugPunktX = this.nockenWelleMitteX + this.nockenWelleRadius;
            this.verdichtungsPunktY = this.nockenWelleMitteY + this.nockenWelleRadius;

            this.explosionsPunktX = this.nockenWelleMitteX - this.nockenWelleRadius;
            this.absaubungsPunktY = this.nockenWelleMitteY - this.nockenWelleRadius;
        }

        /// <summary>
        /// Berechnet die X-Koordinate der Pleustange anhand der Stangenlaenge
        /// und der x und y Koordinate auf der Kurbelwelle und gibt sie wieder.
        /// </summary>
        /// <param name="kreisX">X-Koordinate von einem Punkt auf dem Kreis.</param>
        /// <param name="kreisY">Y-Koordinate von einem Punkt auf dem Kreis.</param>
        /// <returns>Die X-Koordinate der Pleustange.</returns>
        private float BerechneStangenPosiX(float kreisX, float kreisY)
        {

            float diff = 0.0F;

            float stangenLaengerqudrat = this.stangenLaenge * this.stangenLaenge;

            float erg = (stangenLaengerqudrat) - (kreisY * kreisY);//(k^2-y^2)
            float erg2 = (float)Math.Sqrt(erg);//Wurzel aus (k^2-y^2)
            float stangenPosyX = kreisX + erg2;//x + Wurzel aus (k^2-y^2)
            float momentaneLaenge = stangenPosyX - kreisX;

            if (stangenLaenge != momentaneLaenge)
            {
                diff = stangenLaenge - momentaneLaenge;
            }

            stangenPosyX = stangenPosyX + diff;

            return stangenPosyX;
        }

        private void ZeichneSystem(Graphics graphics)
        {

            graphics.Clear(this.BackColor);
            graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

            using (Pen stift = new Pen(Color.Blue, 2))
            {
                this.ZeicheKurbelWelle(graphics, stift);
                
                // Berechnen der Koordinaten auf dem Kreis.
                float kreisPunktX = (float)(this.kreisMitteX + Math.Cos(this.winkel) * this.radius);
                float kreisPunktY = (float)(this.kreisMitteY + Math.Sin(this.winkel) * this.radius);

                //Berchnen der Stangenposition.
                float stangenPunktX = this.BerechneStangenPosiX(kreisPunktX, kreisPunktY);
                float stangenPunktY = this.kreisMitteY;


                //Stange wird gezeichnet.

                this.ZeichnePleulStange(graphics, stift, kreisPunktX, kreisPunktY, stangenPunktX, stangenPunktY);

                //MittelKreis wird gezeichnet.
                graphics.FillEllipse(Brushes.Black, this.kreisMitteX - 4, this.kreisMitteY - 4, 8, 8);

                //Verbindungskreis auf der Kurbellwelle wird gezeichnet.
                graphics.FillEllipse(Brushes.Green,
                    kreisPunktX - 4, kreisPunktY - 4, 8, 8);
                //Verbindungskreis auf der Stange wird gezeichnet
                graphics.FillEllipse(Brushes.Red,
                    stangenPunktX - 4, stangenPunktY - 4, 8, 8);

                this.BerechneUndZeichneKolben(graphics, stangenPunktX, stangenPunktY);
                this.ZeichneNockenWelle(graphics, stift);

                //Zeichne Kette
                stift.Color = Color.Black;
                int erg = this.halbZaehler % 2;
                if (erg == 0) { stift.Color = Color.Wheat; }
                this.halbZaehler++;

                stift.Width = 4;
                graphics.DrawLine(stift, this.kreisMitteX, this.kreisMitteY, this.nockenWelleMitteX, this.nockenWelleMitteY);
                stift.Width = 2;
                stift.Color = Color.Black;
                //einlassStange zeichnen
                graphics.DrawRectangle(stift, this.einlassStange);
                //Stange zum einlassVentil
                graphics.DrawLine(stift, this.einlassVentil.Right, this.einlassVentil.Y, this.einlassStange.Right, this.einlassStange.Y);
                //auslassStange zeichnen
                graphics.DrawRectangle(stift, this.auslassStange);
                //Stange zum auslassVentil

                graphics.DrawLine(stift, this.auslassVentil.Right, this.auslassVentil.Y, this.auslassStange.Right, this.auslassStange.Y);
            }


        }

        private void BerechneUndZeichneKolben(Graphics graphics, float stangenPosiX, float stangenPosiY)
        {
            int xPosi = (int)stangenPosiX;
            int yPosi = (int)stangenPosiY - (int)this.kolbenBreite / 2;
            this.kolbenPosition = new Point(xPosi, yPosi);
            this.kolben.Location = this.kolbenPosition;
            this.ZeichneKolben(graphics);
        }
        private void ZeichneZuendKerze(Graphics graphics, Brush pinsel)
        {
            graphics.FillRectangle(pinsel, this.zuendKerze);
        }

        private void OnPaint(object sender, PaintEventArgs e)
        {
            this.ZeichneSystem(e.Graphics);
            this.ZeichneZylinderhuelle(e.Graphics);

        }

        private void ZeichneZylinderhuelle(Graphics g)
        {
            g.DrawRectangle(this.zylinderFarbe, this.zylinderHuelle);
        }

        private void ZeicheKurbelWelle(Graphics graphics, Pen stift)
        {
            graphics.FillEllipse(Brushes.LightBlue, this.KurbelWelleRechtEck);
            stift.Color = Color.Blue;
            stift.Width = 2;
            graphics.DrawEllipse(stift, this.KurbelWelleRechtEck);
        }

        private void ZeichneKolben(Graphics graphics)
        {
            graphics.FillRectangle(Brushes.Black, this.kolben);
        }

        private void ZeichnePleulStange(Graphics graphics, Pen stift, float kreisPunktX, float kreisPunktY, float stangenPunktX, float stangenPunktY)
        {
            stift.Color = Color.Red;
            stift.Width = 5;
            graphics.DrawLine(stift, kreisPunktX, kreisPunktY, stangenPunktX, stangenPunktY);
        }

        private void ZeichneNockenWelle(Graphics graphics, Pen stift)
        {
            graphics.FillEllipse(Brushes.LightBlue, this.nockenWelleRechtEck);
            stift.Color = Color.Blue;
            stift.Width = 2;
            graphics.DrawEllipse(stift, this.nockenWelleRechtEck);
            float riemenkreisPunktX = (float)(this.nockenWelleMitteX + Math.Cos(this.ventilWinkel) * this.nockenWelleRadius);
            float riemenkreisPunktY = (float)(this.nockenWelleMitteY + Math.Sin(this.ventilWinkel) * this.nockenWelleRadius);
            graphics.FillEllipse(Brushes.Red,
                    riemenkreisPunktX - 10, riemenkreisPunktY - 10, 20, 20);
            //MittelKreis wird gezeichnet.
            graphics.FillEllipse(Brushes.Black, this.nockenWelleMitteX - 4, this.nockenWelleMitteY - 4, 8, 8);
            this.ErmittleTakt(riemenkreisPunktX, riemenkreisPunktY, graphics);
            this.ZeichneTaktZustand(graphics, this.takt);

        }
        private void ZeichneTaktZustand(Graphics graphics, Takt momentanerTakt)
        {
            switch (momentanerTakt)
            {
                case Takt.AnsaugTakt:                    
                    this.ZeichneZuendKerze(graphics, new SolidBrush(this.BackColor));
                    this.einlassStange.Location = this.einlassStangeVerschiebeLoc;
                    this.auslassStange.Location = this.auslassStangeDefaultLoc;
                    this.label1.Text = "1.Takt Ansaugen";
                    graphics.FillRectangle(Brushes.LightBlue, this.kolben.Right, this.kolben.Y,
                        this.zylinderHuelle.Right - this.kolben.Right, this.zylinderHoehe);
                    graphics.FillRectangle(Brushes.Green, this.einlassVentil);
                    graphics.FillRectangle(Brushes.Red, this.auslassVentil);
                    break;
                case Takt.VerdichtungsTakt:                    
                    this.ZeichneZuendKerze(graphics, new SolidBrush(this.BackColor));
                    this.einlassStange.Location = this.einlassStangeDefaultLoc;
                    this.auslassStange.Location = this.auslassStangeDefaultLoc;
                    this.label1.Text = "2.Takt Verdichten";
                    graphics.FillRectangle(Brushes.Blue, this.kolben.Right, this.kolben.Y,
                        this.zylinderHuelle.Right - this.kolben.Right, this.zylinderHoehe);
                    graphics.FillRectangle(Brushes.Red, this.einlassVentil);
                    graphics.FillRectangle(Brushes.Red, this.auslassVentil);
                    break;
                case Takt.ExplosionsTakt:                    
                    this.einlassStange.Location = this.einlassStangeDefaultLoc;
                    this.auslassStange.Location = this.auslassStangeDefaultLoc;
                    this.label1.Text = "3.Takt Arbeiten";
                    graphics.FillRectangle(Brushes.Orange, this.kolben.Right, this.kolben.Y,
                        this.zylinderHuelle.Right - this.kolben.Right, this.zylinderHoehe);
                    graphics.FillRectangle(Brushes.Red, this.einlassVentil);
                    graphics.FillRectangle(Brushes.Red, this.auslassVentil);
                    break;
                case Takt.AbsaugTakt:                    
                    this.ZeichneZuendKerze(graphics, new SolidBrush(this.BackColor));
                    this.einlassStange.Location = this.einlassStangeDefaultLoc;
                    this.auslassStange.Location = this.auslassStangeVerschiebeLoc;
                    this.label1.Text = "4.Takt Auslassen";
                    graphics.FillRectangle(Brushes.Gray, this.kolben.Right, this.kolben.Y,
                        this.zylinderHuelle.Right - this.kolben.Right, this.zylinderHoehe);
                    graphics.FillRectangle(Brushes.Red, this.einlassVentil);
                    graphics.FillRectangle(Brushes.Green, this.auslassVentil);
                    break;
            }

        }

        private void ErmittleTakt(float kurbelWellePunktX, float kurbelWellePunktY, Graphics graphics)
        {
            if (this.ansaugPunktX == kurbelWellePunktX)
            {
                this.takt = Takt.AnsaugTakt;

            }
            if (this.verdichtungsPunktY == kurbelWellePunktY)
            {
                this.takt = Takt.VerdichtungsTakt;

            }
            if (this.explosionsPunktX == kurbelWellePunktX)
            {
                this.takt = Takt.ExplosionsTakt;
                this.ZeichneZuendKerze(graphics, Brushes.Orange);
            }
            if (this.absaubungsPunktY == kurbelWellePunktY)
            {
                this.takt = Takt.AbsaugTakt;

            }
            // return Takte.DerSelbe;

        }
    }
}
